package me.sdevil507.org.controller;

import lombok.extern.slf4j.Slf4j;
import me.sdevil507.biz.common.sms.captcha.service.CaptchaService;
import me.sdevil507.org.dto.IframeLoginParamsDTO;
import me.sdevil507.org.dto.OrgUserLoginParamsDto;
import me.sdevil507.org.dto.OrgUserSmsLoginParamsDTO;
import me.sdevil507.org.events.OrgUserLastLoginTimeEvent;
import me.sdevil507.org.po.OrgDeptPo;
import me.sdevil507.org.po.OrgUserPo;
import me.sdevil507.org.service.OrgDeptService;
import me.sdevil507.org.service.OrgRoleService;
import me.sdevil507.org.service.OrgService;
import me.sdevil507.org.service.OrgUserService;
import me.sdevil507.platform.service.PlatResourceService;
import me.sdevil507.supports.jpa.BaseJpaSnowflakeIdAndAuditEntity;
import me.sdevil507.supports.result.ApiResultDTO;
import me.sdevil507.supports.result.ApiResultGenerator;
import me.sdevil507.supports.shiro.enums.LoginChannel;
import me.sdevil507.supports.shiro.enums.LoginModeType;
import me.sdevil507.supports.shiro.enums.RoleType;
import me.sdevil507.supports.shiro.helper.OrgAccountHelper;
import me.sdevil507.supports.shiro.kickout.ShiroLoginProxy;
import me.sdevil507.supports.shiro.realm.OrgUsernamePasswordRealm;
import me.sdevil507.supports.shiro.token.PhoneNumberToken;
import me.sdevil507.supports.shiro.token.SmsToken;
import me.sdevil507.supports.shiro.token.UsernamePasswordToken;
import me.sdevil507.supports.status.ApiStatusCode;
import me.sdevil507.supports.util.AESUtil;
import me.sdevil507.systemAssist.Constant.SystemAssistConstant;
import me.sdevil507.systemAssist.systemLog.annotation.OperLog;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 机构端用户Controller操作
 *
 * @author sdevil507
 * created on 2019/12/15
 */
@RestController
@RequestMapping("/api/org/user")
@Slf4j
public class OrgUserLoginController {

    @Autowired
    private ShiroLoginProxy shiroLoginProxy;
    @Autowired
    private ApplicationEventPublisher publisher;
    @Autowired
    private OrgService orgService;
    @Autowired
    private OrgRoleService orgRoleService;
    @Autowired
    private OrgUserService orgUserService;
    @Autowired
    private OrgDeptService orgDeptService;
    @Autowired
    private PlatResourceService platResourceService;
    @Autowired
    private OrgUsernamePasswordRealm orgUsernamePasswordRealm;
    @Autowired
    private CaptchaService captchaService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 手机号/密码登录--中移 iframe调用登录  去除图形验证码
     *
     * @param dto 入参dto
     * @return 执行反馈
     */
    @OperLog(operTerminal = SystemAssistConstant.systemAssistTerminal.ORG, operClassify = SystemAssistConstant.systemAssistClassify.SECURITY, operModule = SystemAssistConstant.systemAssistModule.LOGIN, operDesc = "移动iframe嵌入登录", recordRequestParams = false)
    @PostMapping("/noCaptchaLogin")
    public ApiResultDTO noCaptchaLogin(@RequestBody @Valid IframeLoginParamsDTO dto) {

        //解密手机号
        String decryptPhoneNumber = AESUtil.decryptLogin(dto.getPhoneNumber());

        OrgUserPo orgUserPo = orgUserService.readOneByPhoneNumber(decryptPhoneNumber);
        if (null == orgUserPo) {
            // 没该用户
            return ApiResultGenerator.create(ApiStatusCode.ACCOUNT_NOT_EXISTED.getCode(), ApiStatusCode.ACCOUNT_NOT_EXISTED.getDescription());
        }
        //是否被锁定
        if(orgUserPo.getLocked()){
            return ApiResultGenerator.create(ApiStatusCode.ACCOUNT_LOCKED.getCode(), ApiStatusCode.ACCOUNT_LOCKED.getDescription());
        }
        //查询用户角色
        this.setUserRoleInfo(orgUserPo);

        // 组织机构用户
        PhoneNumberToken phoneNumberToken = new PhoneNumberToken(orgUserPo.getPhoneNumber(), LoginChannel.IFRAME, LoginModeType.ENCRYPT_PHONENUMBER);
        shiroLoginProxy.login(phoneNumberToken);
        String token = SecurityUtils.getSubject().getSession().getId().toString();
        // 发布更新最后登录时间事件
        publisher.publishEvent(new OrgUserLastLoginTimeEvent(this, OrgAccountHelper.getUsername(), new Date()));
        // 清除缓存
        orgUsernamePasswordRealm.clearCachedInfo(SecurityUtils.getSubject().getPrincipal().toString());
        //获取用户所有的权限模块
        Set<String> permissionsCodeList = orgRoleService.findPermissions();

        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("authCodes", permissionsCodeList);

        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), map);
    }

    /**
     * 手机号/密码登录
     *
     * @param dto 入参dto
     * @return 执行反馈
     */
    @OperLog(operTerminal = SystemAssistConstant.systemAssistTerminal.ORG, operClassify = SystemAssistConstant.systemAssistClassify.SECURITY, operModule = SystemAssistConstant.systemAssistModule.LOGIN, operDesc = "", recordRequestParams = false)
    @PostMapping("/login")
    public ApiResultDTO login(@RequestBody @Valid OrgUserLoginParamsDto dto, HttpServletRequest request) {

        //验证码是否正确
        String key = captchaService.getImgCaptchaKey(request);
        String redisCaptcha = stringRedisTemplate.opsForValue().get(key);

        if (redisCaptcha != null) {
            if (!redisCaptcha.toUpperCase().equals(dto.getCaptcha().toUpperCase())) {
                return ApiResultGenerator.create(ApiStatusCode.CAPTCHA_ERROR.getCode(), ApiStatusCode.CAPTCHA_ERROR.getDescription());
            }
        } else {
            return ApiResultGenerator.create(ApiStatusCode.CAPTCHA_EXPIRED.getCode(), ApiStatusCode.CAPTCHA_EXPIRED.getDescription());
        }

        String phoneNumber = AESUtil.decryptLogin(dto.getPhoneNumber());
        String password = AESUtil.decryptLogin(dto.getPassword());
//        log.info("----phoneNumber=="+phoneNumber + "----pass--"+ password);
//        String passwordSalt = "fzCE";
//        String encryptPassword = DigestUtils.md5Hex(String.format("%s%s", password, passwordSalt));
//        log.info("----encryptPassword=="+encryptPassword);

        OrgUserPo orgUserPo = orgUserService.readOneByPhoneNumber(phoneNumber);
        if (null == orgUserPo) {
            // 没该用户
            return ApiResultGenerator.create(ApiStatusCode.ACCOUNT_NOT_EXISTED.getCode(), ApiStatusCode.ACCOUNT_NOT_EXISTED.getDescription());
        }
        //是否被锁定
        if(orgUserPo.getLocked()){
            return ApiResultGenerator.create(ApiStatusCode.ACCOUNT_LOCKED.getCode(), ApiStatusCode.ACCOUNT_LOCKED.getDescription());
        }
        //查询用户角色
        this.setUserRoleInfo(orgUserPo);

        // 组织机构用户---SimpleHash和DigestUtils.md5Hex加密不一样，传入password+salt,并在realm中不传入salt
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(phoneNumber, password+orgUserPo.getSalt(), LoginChannel.ORG, LoginModeType.USERNAME_PASSWORD);
        shiroLoginProxy.login(usernamePasswordToken);
        String token = SecurityUtils.getSubject().getSession().getId().toString();
        // 发布更新最后登录时间事件
        publisher.publishEvent(new OrgUserLastLoginTimeEvent(this, OrgAccountHelper.getUsername(), new Date()));

        // 清除缓存
        orgUsernamePasswordRealm.clearCachedInfo(SecurityUtils.getSubject().getPrincipal().toString());
        return ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), token);
    }

    /**
     * 短信登录
     *
     * @param dto 短信登录入参dto
     * @return 执行反馈
     */
    @OperLog(operTerminal = SystemAssistConstant.systemAssistTerminal.EXPERT, operClassify = SystemAssistConstant.systemAssistClassify.SECURITY, operModule = SystemAssistConstant.systemAssistModule.LOGIN, operDesc = "短信验证码登录", recordRequestParams = false)
    @PostMapping("/smsLogin")
    public ApiResultDTO smsLogin(@RequestBody @Valid OrgUserSmsLoginParamsDTO dto) {
        String phoneNumber = AESUtil.decryptLogin(dto.getPhoneNumber());
        OrgUserPo orgUserPo = orgUserService.readOneByPhoneNumber(phoneNumber);
        if (null == orgUserPo) {
            // 没该用户
            return ApiResultGenerator.create(ApiStatusCode.ACCOUNT_NOT_EXISTED.getCode(), ApiStatusCode.ACCOUNT_NOT_EXISTED.getDescription());
        }
        if(orgUserPo.getLocked()){
            return ApiResultGenerator.create(ApiStatusCode.ACCOUNT_LOCKED.getCode(), ApiStatusCode.ACCOUNT_LOCKED.getDescription());
        }
        //查询用户角色
        this.setUserRoleInfo(orgUserPo);
        SmsToken smsToken = new SmsToken(phoneNumber, dto.getCode(), LoginChannel.ORG, LoginModeType.SMS);
        shiroLoginProxy.login(smsToken);
        String token = SecurityUtils.getSubject().getSession().getId().toString();
        ApiResultDTO apiResultDTO = ApiResultGenerator.create(ApiStatusCode.SUCCESS.getCode(), ApiStatusCode.SUCCESS.getDescription(), token);
        // 发布更新最后登录时间事件
        publisher.publishEvent(new OrgUserLastLoginTimeEvent(this, OrgAccountHelper.getUsername(), new Date()));
        // 清除缓存
        orgUsernamePasswordRealm.clearCachedInfo(SecurityUtils.getSubject().getPrincipal().toString());
        return apiResultDTO;
    }

    private void setUserRoleInfo(OrgUserPo orgUserPo){
        //查询用户角色
        if(!CollectionUtils.isEmpty(orgUserPo.getOrgUserRel())){
            //代表至少有机构或者专家角色
            if (orgUserService.containsMgr(orgUserPo.getId())) {
                // 管理员角色--获取在某个机构下是管理员的机构id
                Long deptId = orgService.getOrgIdByUserId(orgUserPo.getId());
//                OrgPo orgPo = orgService.readOne(orgId);
                OrgDeptPo orgDeptPo = orgDeptService.getOne(deptId);
                OrgAccountHelper.setOrgId(deptId);
                OrgAccountHelper.setOrgName(orgDeptPo.getTitle());
                OrgAccountHelper.setOrgType(RoleType.MGR.name());
                //判断当前用户与登陆域名是否匹配
//                if(!StringUtils.isEmpty(dto.getPreDomainName()) && !dto.getPreDomainName().equals(orgPo.getPreDomainName())){
//                    // 没权限登录
//                    return ApiResultGenerator.create(ApiStatusCode.ACCOUNT_CHANNEL_NOT_ALLOWED.getCode(), ApiStatusCode.ACCOUNT_CHANNEL_NOT_ALLOWED.getDescription());
//                }
            }else{
                // 专家角色
                OrgAccountHelper.setOrgType(RoleType.EXPERT.name());
            }
        }else{
            // 平台角色
            OrgAccountHelper.setOrgType(RoleType.PLATFORM.name());
        }
        OrgAccountHelper.setUserId(orgUserPo.getId());
        if(!OrgAccountHelper.getOrgType().equals(RoleType.EXPERT.name())){
            OrgAccountHelper.setDeptId(!CollectionUtils.isEmpty(orgUserPo.getDepts()) ? orgUserPo.getDepts().get(0).getId() : null);
            OrgAccountHelper.setOrgIdList(!CollectionUtils.isEmpty(orgUserPo.getDepts()) ? orgUserPo.getDepts().stream().map(BaseJpaSnowflakeIdAndAuditEntity::getId).collect(Collectors.toSet()): null);
            //设置用户的orgList
//            OrgAccountHelper.setOrgIdList(
//                    orgUserPo.getRoles().stream().flatMap(orgRolePo -> orgRolePo.getOrgs().stream())
//                            .map(OrgPo::getId).collect(Collectors.toSet())
//            );
        }
    }
}
